/*
 * archivos_abiertos.c
 *
 *  Created on: 20/10/2011
 *      Author: utn_so
 */

#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "estaticas.h"
#include "estructuras.h"
#include "archivos_abiertos.h"
#include "iniciarFat.h"
#include "log.h"
#include "cache.h"




uint32_t ListaArchivosAbiertosVacia(struct nodoListaArchivosAbiertos *lista)
{
   if (lista == NULL)
	   return 1;
   else
	   return 0;
}



uint32_t InsertarArchivoAbierto(struct nodoListaArchivosAbiertos **lista, char *path, uint32_t iClus)
{
	/*
	 * 	Si ya está en la lista se suma la cantidad de aperturas.
	 * 	Sino se agrega el nodo del archivo y se inicializa la cache
	 */

	struct nodoListaArchivosAbiertos *nuevo, *anterior, *ptr;


	if(!ListaArchivosAbiertosVacia(*lista))
	{
		ptr = *lista;
		while (ptr->cluster != iClus && ptr->sgte != 0)
			ptr = ptr->sgte;

		if (ptr->cluster == iClus)
		{
			ptr->cantidadAperturas++;
			return 0;
		}
	}

	/* Crear un nodo nuevo */
	nuevo = (struct nodoListaArchivosAbiertos *) malloc (sizeof(struct nodoListaArchivosAbiertos));
	nuevo->cluster = iClus;
	nuevo->cantidadAperturas = 1;
	nuevo->path  = (char *) malloc (strlen(path)+1);	//fixme agrego + 1
	nuevo->cache = iniciarCache();
	strcpy(nuevo->path , path);



	/* Si la lista está vacía */
	if(ListaArchivosAbiertosVacia(*lista))
	{
      /* Añadimos la lista a continuación del nuevo nodo */
		nuevo->sgte = *lista;
      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
		*lista = nuevo;

	}
	else
	{
		if ((*lista)->cluster > iClus)
		{
		      /* Añadimos la lista a continuación del nuevo nodo */
				nuevo->sgte = *lista;
		      /* Ahora, el comienzo de nuestra lista es en nuevo nodo */
				*lista = nuevo;
		}
		else
		{
			anterior = *lista;
			/* Avanzamos hasta el último elemento o hasta que el siguiente tenga
         	 un valor mayor que v */
			while(anterior->sgte && anterior->sgte->cluster <= iClus)
				anterior = anterior->sgte;
			/* Insertamos el nuevo nodo después del nodo anterior */
			nuevo->sgte = anterior->sgte;
			anterior->sgte = nuevo;
		}
	}
	return 0;
};


uint32_t BorrarArchivoAbierto(struct nodoListaArchivosAbiertos **lista, char *path)
{
	/*
	 * 		Se utiliza al cerrar un Archivo, en caso de que se haya abierto una sola vez
	 * 		se borra el archivo de la lista. Sino, se resta la cantidad de Aperturas.
	 */
   struct nodoListaArchivosAbiertos *anterior, *nodo;

   nodo = *lista;
   anterior = NULL;
   while(nodo && strcmp(nodo->path, path) != 0) /*nodo!=NULL && nodo->path != path*/
   {
      anterior = nodo;
      nodo = nodo->sgte;
   }
   if(nodo == NULL)
   {
	   return -1; /* El archivo no está abierto */
   }
   else
   {
      if (nodo->cantidadAperturas > 1) /* restar cantidad de aperturas */
    	  nodo->cantidadAperturas--;

      else	/* borrar nodo */
      {
    	  if(anterior == NULL) /* Primer elemento */
    	  {
    		  anterior = *lista;
    		  *lista = nodo->sgte;
    		  anterior->cache = NULL;
    		  anterior->path = NULL;
    		  free(anterior->cache);
    		  free(anterior->path);
    		  free(anterior);
    		  return 0;
    	  }

    	  else  /* un elemento cualquiera */
         	  anterior->sgte = nodo->sgte;
      	  free(nodo->cache);
      	  free(nodo->path);
    	  free(nodo);
      }
      return 0;
   }
}


void BorrarListaArchivosAbiertos(struct nodoListaArchivosAbiertos *lista) // Borrar Archivos Abiertos
{
	struct nodoListaArchivosAbiertos *nodo;

	while(lista)
	{
		nodo = lista;
		lista = nodo->sgte;
		free(nodo);
	}
}


void MostrarArchivosAbiertos(struct nodoListaArchivosAbiertos *lista)
{
   struct nodoListaArchivosAbiertos *nodo;
   nodo = lista;

   if(ListaArchivosAbiertosVacia(lista))
	   printf("No hay Archivos Abiertos\n");

   else
   {
      while(nodo != 0) /* null */
      {
         printf("%s\n", nodo->path);
         nodo = nodo->sgte;
      }
      printf("\n");
   }
}

uint32_t estaAbierto(const char *path)
{
	pthread_mutex_lock(&mutexArchivosAbiertos);
	struct nodoListaArchivosAbiertos *ptr;
	ptr = archivosAbiertos;
	while (ptr != NULL && strcmp(ptr->path,path))
		ptr = ptr->sgte;

	pthread_mutex_unlock(&mutexArchivosAbiertos);
	if (ptr != NULL)
		return 1;
	else
		return 0;
}

uint32_t cantidadDeVecesAbierto(const char *path) {
//	log_info(log, "ARCHIVOS ABIERTOS", "Iniciando cantidadDeVecesabierto");

	struct nodoListaArchivosAbiertos *punteroParaRecorrer;
	pthread_mutex_lock(&mutexArchivosAbiertos);
	punteroParaRecorrer = archivosAbiertos;

	uint32_t cantidadDeVecesAbierto = 0;
	while (punteroParaRecorrer != NULL) {
		if (strcmp(punteroParaRecorrer->path, path) == 0){
//			log_info(
//								log,
//								"ARCHIVOS ABIERTOS",
//								"Se encontró el path en la cola de Archivos Abiertos, hay que retornar su cantidad de aperturas.");
			return punteroParaRecorrer->cantidadAperturas;}

		punteroParaRecorrer = punteroParaRecorrer->sgte;
	}
	pthread_mutex_unlock(&mutexArchivosAbiertos);
	log_error(log, "ARCHIVOS ABIERTOS",
				"No se encontró el path en la cola de Archivos Abiertos");
	return -1;
}

struct colaDeCache * buscarCacheDeUnArchivo(const char *path) {

	/*	en base al path de un archivo, retorna el valor del puntero a la cache
	 *  si el archivo no está abierto, retorna NULL
	 */
//	log_info(log, "ARCHIVOS ABIERTOS", "Iniciando borrarCache");

	struct nodoListaArchivosAbiertos *punteroParaRecorrer;

	punteroParaRecorrer = archivosAbiertos;

	uint32_t cantidadDeVecesAbierto = 0;
	while (punteroParaRecorrer != NULL)
	{
		if (strcmp(punteroParaRecorrer->path, path) == 0)
		{

//			log_info(
//					log,
//					"ARCHIVOS ABIERTOS",
//					"Se encontró el path en la cola de Archivos Abiertos, hay que retornar el puntero.");
			return punteroParaRecorrer->cache;
		}
		punteroParaRecorrer = punteroParaRecorrer->sgte;

	}
	log_error(log, "ARCHIVOS ABIERTOS",
			"No se encontró el path en la cola de Archivos Abiertos");
	return NULL;
}

